package com.onpositive.mediawiki.dataminer;


import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;

import org.eclipse.jface.dialogs.Dialog;

import storage.v1.DBStorage;

import com.onpositive.commons.xml.language.DOMEvaluator;
import com.onpositive.dataminer.core.DataProviderConfig;
import com.onpositive.dataminer.core.IDataProviderConfigurator;
import com.onpositive.mediawiki.redirects.WikipediaRefsRedirector;
import com.onpositive.semantic.model.binding.Binding;
import com.onpositive.semantic.model.ui.generic.IDisplayable;
import com.onpositive.wiki3.db.IWikiDB;
import com.onpositive.wiki3.db.LocationProperties;
import com.onpositive.wiki3.db.impl.WikiDBImpl;

public class MediaWikiConfigurator implements IDataProviderConfigurator {

	static IWikiDB wikiDB;
	public MediaWikiConfigurator() {
	}

	@Override
	public boolean configure(DataProviderConfig config) {
		try {
			Binding pContext = new Binding(config);
			IDisplayable r = (IDisplayable) DOMEvaluator.getInstance()
					.evaluateLocalPluginResource(MediaWikiDataProvider.class,
							"config.dlf", pContext);
			int openWidget = r.openWidget();
			if(openWidget != Dialog.OK)
				return false;
			
			
			ArrayList<WikiEntry> list = selectEntries(config.getUrl());
			if(list==null||list.isEmpty())
				return false;
			
			pContext = new Binding();
			int openWidget1 = selectCategories(pContext, list);
			if(openWidget1 != Dialog.OK)
				return false;
			
			ArrayList<String> toIgnore = new ArrayList<String>();
			for(WikiEntry we : list){
				if(we.isEnabled())
					continue;
				
				toIgnore.add(we.getTitle());
			}
			config.setToIgnore(toIgnore);
			
		} catch (Exception e) {			
			e.printStackTrace();
		}
		return true;
	}

	private int selectCategories(Binding pContext, ArrayList<WikiEntry> list)
			throws Exception {
		
		Binding listBinding = new Binding(list);
		listBinding.setId("list");
		pContext.addChild(listBinding);
		
		IDisplayable q = (IDisplayable) DOMEvaluator.getInstance()
				.evaluateLocalPluginResource(MediaWikiDataProvider.class,
						"categoriesTree.dlf", pContext);
		int openWidget1 = q.openWidget();
		return openWidget1;
	}
	
	private ArrayList<WikiEntry> selectEntries(String rootUrl) {
		if(rootUrl==null||rootUrl.trim().isEmpty())
			return null;
		
		if(wikiDB==null)
			wikiDB = WikipediaRefsRedirector.wikiDBImpl;

		HashMap<String,WikiEntry> map = new HashMap<String, MediaWikiConfigurator.WikiEntry>();
		ArrayList<WikiEntry> list = new ArrayList<MediaWikiConfigurator.WikiEntry>();
		try {
			DBStorage dbStorage = new DBStorage(wikiDB);			
			String normalized = rootUrl;//.toLowerCase().replace(' ','_');
			
			WikiEntry rootEntry = new WikiEntry(normalized);
			rootEntry.setLevel(0);
			list.add(rootEntry);
			map.put(rootEntry.getTitle(), rootEntry);
			for(int i = 0 ; i < list.size() ; i++){
				
				WikiEntry entry = list.get(i);
				String title = entry.getTitle();			
					
				Collection<String> members = dbStorage.getChildren(title);
				if(members==null)
					continue;
				
l0:				for(String s : members){
					if(s.toLowerCase().equals(title.toLowerCase()))
						continue;
					
					WikiEntry e = map.get(s);					
					if(e==null){					
						e = new WikiEntry(s);
						map.put(e.getTitle(), e);
						list.add(e);
					}
					else{
						
						for(Collection<WikiEntry> c : entry.getAllAncestors()){
							if(c.contains(e))
								continue l0;
						}						
					}
					e.addParent(entry);
					entry.setLeaf(false);
				}
			}	
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		ArrayList<WikiEntry> result = new ArrayList<MediaWikiConfigurator.WikiEntry>();
		for(WikiEntry e : list){
			e.clearAncestors();
			if(!e.isLeaf())
				result.add(e);
		}
		return result;
	}

	public static class WikiEntry{
		
		boolean isLeaf = true;
		
		String title;
		
		HashSet<WikiEntry> parents;
		
		int level;
		
		HashSet<Collection<WikiEntry>> allAncestors = new HashSet<Collection<WikiEntry>>();
		
		public WikiEntry(String title) {
			super();
			this.title = title;
			this.level = -1;
		}

		public void clearAncestors() {
			allAncestors=null;			
		}

		boolean enabled=true;

		public String getTitle() {
			return title;
		}

		public void setTitle(String title) {
			this.title = title;
		}

		public HashSet<WikiEntry> getParents() {
			return parents;
		}

		public void setParents(HashSet<WikiEntry> parents) {
			this.parents = parents;
		}
		
		public void addParent(WikiEntry parent) {
			if(this.parents==null){				
				this.parents= new HashSet<MediaWikiConfigurator.WikiEntry>();
				this.allAncestors.add(parents);
			}
			
			int l = parent.getLevel()+1;
			if(this.level<0){				
				this.level = l;
			}
			else{
				this.level = Math.min(this.level, l);
			}
			this.parents.add(parent);
			this.allAncestors.addAll(parent.getAllAncestors());
		}

		public boolean isEnabled() {
			return enabled;
		}

		public void setEnabled(boolean enabled) {
			this.enabled = enabled;
		}
		
		@Override
		public String toString() {
			return title;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((title == null) ? 0 : title.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			WikiEntry other = (WikiEntry) obj;
			if (title == null) {
				if (other.title != null)
					return false;
			} else if (!title.equals(other.title))
				return false;
			return true;
		}

		public int getLevel() {
			return level;
		}

		public void setLevel(int level) {
			this.level = level;
		}

		public Collection<Collection<WikiEntry>> getAllAncestors() {
			return allAncestors;
		}

		public boolean isLeaf() {
			return isLeaf;
		}

		public void setLeaf(boolean isLeaf) {
			this.isLeaf = isLeaf;
		}
	}	

}
